// Fill out your copyright notice in the Description page of Project Settings.


#include "Component/FreezeTime.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "Actor/MovableActor.h"

// Sets default values for this component's properties
UFreezeTime::UFreezeTime()
{
	PrimaryComponentTick.bCanEverTick = false;
	FreezeValue = 0.0001;
	FreezePlayerValue = 1.f;
	PPSettings = FPostProcessSettings();
}


// Called when the game starts
void UFreezeTime::BeginPlay()
{
	Super::BeginPlay();
	
}

void UFreezeTime::ActivateAbility()
{
	Character = Cast<ACharacter>(GetOwner());
	if (!Character) {
		return;
	}
	
	if (!IsFreezeTimeActive) {
		if (UseTrace) {
			TArray<FHitResult> HitResultes;
			Trace(HitResultes);
			for (int32 HitIdx = 0; HitIdx < HitResultes.Num(); HitIdx++){
				HitActors.Push(HitResultes[HitIdx].GetActor());
				HitResultes[HitIdx].GetActor()->CustomTimeDilation = FreezeValue;
				UStaticMeshComponent* TempMesh = Cast<UStaticMeshComponent>(Character->GetComponentByClass(UStaticMeshComponent::StaticClass()));
				if (!TempMesh) {
					return;
				}
				Velocity.Insert(TempMesh->GetPhysicsLinearVelocity(), HitIdx);
				TempMesh->SetSimulatePhysics(false);
			}
			IsFreezeTimeActive = true;
		}
		else {
			UCameraComponent* TempCamera = Cast<UCameraComponent>(Character->GetComponentByClass(UCameraComponent::StaticClass()));
			IsFreezeTimeActive = true;
			if (TempCamera) {
				TempCamera->PostProcessSettings = PPSettings;
			}
			if (IncludePlayer) {
				FreezePlayerValue = FreezeValue;
			}
			else {
				FreezePlayerValue = 1.f / FreezeValue;
			}
			UGameplayStatics::SetGlobalTimeDilation(this,FreezeValue);
			UGameplayStatics::SetGlobalPitchModulation(this, FreezeValue, 0.f);
			FTimerHandle UniqueHandle;
			FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject(this, &UFreezeTime::SetOwnerTimeDilation, FreezePlayerValue);
			GetWorld()->GetTimerManager().SetTimer(UniqueHandle, RespawnDelegate, 0.00001, false);
		}
	}
	else {
		DeactivateAbility();
	}
}

void UFreezeTime::DeactivateAbility()
{
	IsFreezeTimeActive = false;
	if (!UseTrace) {
		UCameraComponent* TempCamera = Cast<UCameraComponent>(Character->GetComponentByClass(UCameraComponent::StaticClass()));
		if (TempCamera) {
			TempCamera->PostProcessSettings = FPostProcessSettings();
		}
		UGameplayStatics::SetGlobalTimeDilation(this, 1.f);
		UGameplayStatics::SetGlobalPitchModulation(this, 1.f, 0.f);
		Character->CustomTimeDilation = 1.f;
	}
	else {
		for (int32 HitIdx = 0; HitIdx < HitActors.Num(); HitIdx++) {
			HitActors[HitIdx]->CustomTimeDilation = 1.f;
			UStaticMeshComponent* TempMesh = Cast<UStaticMeshComponent>(Character->GetComponentByClass(UStaticMeshComponent::StaticClass()));
			if (!TempMesh) {
				return;
			}
			if (HitActors[HitIdx]->GetClass()!= AMovableActor::StaticClass()) {
				TempMesh->SetSimulatePhysics(true);
				TempMesh->SetAllPhysicsLinearVelocity(Velocity[HitIdx],true);
			}
		}
		HitActors.Empty();
	}
}

void UFreezeTime::Trace(TArray<FHitResult>& HitResultes)
{
	check(Character);
	USceneComponent* Temp=Cast<USceneComponent>(Character->GetComponentByClass(UCameraComponent::StaticClass()));
	check(Temp);
	FVector Start = Temp->GetComponentLocation();
	FVector Director = Temp->GetForwardVector();
	TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
	ObjectTypes.Push(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
	ObjectTypes.Push(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_PhysicsBody));
	UKismetSystemLibrary::SphereTraceMultiForObjects(this, Start+ Director*300, Start + Director * 1000,50, ObjectTypes,  false, TArray<AActor*>(), EDrawDebugTrace::ForDuration, HitResultes, true);

}

void UFreezeTime::SetOwnerTimeDilation(float TimeDilation) {
	Character->CustomTimeDilation = TimeDilation;
}
